/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bookstore.mvc.controller;

import bookstore.bean.LoginBean;

import bookstore.jaxb.Order;
import bookstore.jaxb.OrderDetails;
import bookstore.jaxb.UserInfo;
import bookstore.util.Utilities;
import bookstore.validator.JAXBBookStoreValidationHandler;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 *
 * @author nhvkhanh
 */
public class Controller extends HttpServlet {

    /** 
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        HttpSession session = request.getSession();
        try {
            String action = request.getParameter("action");
            ServletContext context = getServletContext();
            String realContextPath = context.getRealPath("/");
            String realPath = realContextPath + "WEB-INF/BooksFile.xml";
            File booksFile = new File(realPath);
            if (!booksFile.exists()) {
                Utilities.createXMLSourceFile(realPath);
            }

            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(new File(realPath));

            //SEARCH

            if (action.equals("Search")) {
                //get the title from request
                String query = request.getParameter("q");
                XPathFactory xpf = XPathFactory.newInstance();
                XPath xpath = xpf.newXPath();
                String expression = "//Book/Title[contains(.,\"" + query + "\")]/..";
                NodeList list = (NodeList) xpath.evaluate(expression, doc, XPathConstants.NODESET);


                XMLOutputFactory ouf = XMLOutputFactory.newInstance();
                StringWriter sw = new StringWriter();
                XMLStreamWriter writer = ouf.createXMLStreamWriter(response.getWriter());
                writer.writeStartDocument();
                writer.writeStartElement("Books");
                for (int i = 0; i < list.getLength(); i++) {
                    Node node = list.item(i);//Book Node
                    NodeList childrenNode = node.getChildNodes();
                    writer.writeStartElement("Book");
                    for (int j = 0; j < childrenNode.getLength(); j++) {
                        Node child = childrenNode.item(j);
                        if (child.getNodeName().equals("Isbn") || child.getNodeName().equals("Title") || child.getNodeName().equals("Url")
                                || child.getNodeName().equals("Author")) {
                            writer.writeStartElement(child.getNodeName());
                            writer.writeCharacters(child.getTextContent());
                            writer.writeEndElement();
                        }
                    }
                    writer.writeEndElement();
                }
                writer.writeEndElement();
                writer.writeEndDocument();
                writer.flush();
                writer.close();
                response.getWriter().flush();
            } else if (action.equals("BookDetails")) {
                String isbn = request.getParameter("isbn");
                String url = "bookDetail.jsp" + "?isbn=" + isbn;
                RequestDispatcher rd = request.getRequestDispatcher(url);
                rd.forward(request, response);
            } else if (action.equals("Checkout")) {
                //User Information
                //HttpSession session = request.getSession();
                //String userName = (String)session.getAttribute("userName");
                //userName is not null - Logged In
                //if (!userName.equals("") && userName!=null)
                // {
                //find information
                // }
                //Marshalling to XML and send response
                LoginBean user = (LoginBean) session.getAttribute("USER");
                if (!user.getUsername().equals("GUEST")) {
                    UserInfo userInfo = Utilities.GetUserInfo(user.getUsername());
                    JAXBContext ctx = JAXBContext.newInstance(UserInfo.class);
                    Marshaller mar = ctx.createMarshaller();
                    mar.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
                    mar.marshal(userInfo, response.getWriter());
                }

            } else if (action.equals("Complete")) {
                String orderDetailsStr = request.getParameter("orderDetail");
                String userInfo = request.getParameter("order");
                //String orderDetailsStr = "<OrderDetails xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.bookstore.net/schema/order' xsi:schemaLocation='http://www.bookstore.net/schema/order OrderSchema.xml'>    <OrderDetail Isbn='ISBN9780385345224'>        <Quantity>2</Quantity>    </OrderDetail>    <OrderDetail Isbn='ISBN9781416595212'>        <Quantity>2</Quantity>    </OrderDetail></OrderDetails>";//request.getParameter("order");
                //String userInfo = "<Order xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.bookstore.net/schema/order' xsi:schemaLocation='http://www.bookstore.net/schema/order OrderSchema.xml'>  <City>Da Nang</City>    <Name>Vikey</Name>    <OrderTime>25-01-2011</OrderTime>    <Phone>000919319316</Phone>    <Username>UserName</Username>    <Address>452/1</Address></Order>";//request.getParameter("userInfo");
                //Get Information to write to Order Table
                String schemaPath = realContextPath + "/schemas/OrderSchema.xml";
                Order order = (Order) Utilities.customUnMarshall(schemaPath, userInfo, response, false);
                if (order != null) {
                    OrderDetails orderDetails = (OrderDetails) Utilities.customUnMarshall(schemaPath, orderDetailsStr, response, false);
                    String tempFilePath = realContextPath + "/temporary/";
                    String result = Utilities.insertOrder(order, orderDetails, doc, tempFilePath);
                    if (result != null) {
                        Utilities.createResponseMessage(response.getWriter(), result, "OK");
                    } else {
                        Utilities.createResponseMessage(response.getWriter(), "Some thing went wrong.", "NG");
                    }
                }




            } else if (action.equals("download")) {
                String orderId = request.getParameter("orderId");
                String xsltPath = realContextPath + "WEB-INF/xsl/Order.xsl";
                String orderDetailsPath = realContextPath + "temporary/OrderDetailsToPDF" + orderId + ".xml";
                String orderPath = realContextPath + "temporary/OrderToPDF" + orderId + ".xml";
                String ouputFilePath = realContextPath + "temporary/Order" + orderId + ".pdf";
                Utilities.GeneratePDF(xsltPath, ouputFilePath, orderPath, orderDetailsPath);

                File file = new File(ouputFilePath);

                // Get content type by filename.
                String contentType = getServletContext().getMimeType(file.getName());

                // If content type is unknown, then set the default value.
                // For all content types, see: http://www.w3schools.com/media/media_mimeref.asp
                // To add new content types, add new mime-mapping entry in web.xml.
                if (contentType == null) {
                    contentType = "application/octet-stream";
                }

                // Init servlet response.
                response.reset();
                response.setBufferSize(10240);
                response.setContentType(contentType);
                response.setHeader("Content-Length", String.valueOf(file.length()));
                response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");

                // Prepare streams.
                BufferedInputStream input = null;
                BufferedOutputStream output = null;

                try {
                    // Open streams.
                    input = new BufferedInputStream(new FileInputStream(file), 10240);
                    output = new BufferedOutputStream(response.getOutputStream(), 10240);

                    // Write file contents to response.
                    byte[] buffer = new byte[10240];
                    int length;
                    while ((length = input.read(buffer)) > 0) {
                        output.write(buffer, 0, length);
                    }
                } finally {
                    // Gently close streams.
                    close(output);
                    close(input);
                }


            } else if (action.equals("homepage")) {
                response.getWriter().write(Utilities.GetHomePageHtml());
            }

        } catch (JAXBException ex) {
            Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
        } catch (XMLStreamException ex) {
            Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
        } catch (XPathExpressionException ex) {
            Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SAXException ex) {
            Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            out.close();
        }
    }

    private static void close(Closeable resource) {
        if (resource != null) {
            try {
                resource.close();
            } catch (IOException e) {
                // Do your thing with the exception. Print it, log it or mail it.
                e.printStackTrace();
            }
        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
